#pragma once 
// 这个文件模拟实现C++的智能指针
#include <mutex>


template<class T>
struct defaultDelete
{
  void operator()(T *ptr)
  {
    delete(ptr);
  }
};

// 这个版本还不完整，没有定制删除器
template <class T,class D=defaultDelete<T>>
class uniquePtr
{
  public:
    uniquePtr(T *ptr)
      :_ptr(ptr)
    {}
    ~uniquePtr()
    {
      D del;
      del(_ptr);
    }
    uniquePtr(const uniquePtr<T>& up) = delete;
    uniquePtr<T>& operator=(const uniquePtr<T> &up) = delete;
    T& operator*()
    {
      return *_ptr;
    }
    
    T* operator->()
    {
      return _ptr;
    }
  protected:
    T *_ptr;
};



template <class T,class D=defaultDelete<T>>
class sharedPtr
{
  public:
    sharedPtr(T *ptr = nullptr)
      :_ptr(ptr),_count(new int(1)),_pmtx(new std::mutex)
    {}

    ~sharedPtr()
    {
      release();
    }

    void release()
    {
        _pmtx->lock();
        bool flag = false;
        if(--(*_count) == 0)
        {
         // delete _ptr;
          D del;
          del(_ptr);
          delete _count;
          flag = true;
        }
        _pmtx->unlock();
        if(flag) delete _pmtx;
    }
    // 拷贝构造
    sharedPtr(const sharedPtr<T> &sp)
      :_ptr(sp._ptr),_count(sp._count),_pmtx(sp._pmtx)
    {
      _pmtx->lock();
      (*_count)++;
      _pmtx->unlock();
    }

    sharedPtr<T>& operator=(const sharedPtr<T> &sp)
    {
      if(this != &sp)// 不能自己给自己赋值
      {
        _pmtx->lock();
        release();
        _pmtx->unlock();
        _ptr = sp._ptr;
        _count = sp._count;
        _pmtx->lock();
        (*_count)++;
        _pmtx->unlock();
      }
      return *this;
    }

    int use_count()
    {
      return *_count;
    }
  
    T *get() const
    {
      return _ptr;
    }


    T& operator*()
    {
      return *_ptr;
    }


    T *operator->()
    {
      return _ptr;
    }
  protected:
    T *_ptr;
    int *_count;
    std::mutex* _pmtx;// 加锁保证计数器的线程安全
};



template<class T>
class weakPtr
{
  public:
    weakPtr(T *ptr = nullptr)
      :_ptr(ptr)
    {}

    weakPtr(const sharedPtr<T>& wp)
      :_ptr(wp.get())
    {}

    weakPtr<T> &operator=(const sharedPtr<T> &wp)
    {
      _ptr = wp.get();
      return *this;
    }
  protected:
    T *_ptr;
};
